﻿//-----------------------------------------------------------------------
// <copyright file="WebflowDeserializer.cs" company="Sławomir Rosiek">
//     Copyright (c) Sławomir Rosiek. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------

namespace Rosieks.Web.Flow.Metadata
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Xml.Linq;

    public class WebflowDeserializer
    {
        private IDictionary<string, Func<XElement, State>> stateTypes = new Dictionary<string, Func<XElement, State>>
            {
                {"viewState", e => WebflowDeserializer.GetViewState(e) },
            };

        public WebflowModel Deserialize(Stream stream)
        {
            var xml = XDocument.Load(stream);

            var webflowElement = xml.Element(GetName("webflowModel"));
            var name = webflowElement.Attribute("name").Value;
            var states = this.GetStates(webflowElement);
            var firstState = this.GetFirstState(states, webflowElement);

            var model = new WebflowModel(name)
            {
                States = states,
                FirstState = firstState,
            };

            return model;
        }

        private static State GetViewState(XElement stateElement)
        {
            return new ViewState(stateElement.Attribute("name").Value);
        }

        private static XName GetName(string name)
        {
            return XName.Get(name, "http://schemas.microsoft.com/dsltools/Webflow");
        }

        private State GetFirstState(IEnumerable<State> states, XElement webflowElement)
        {
            var name = webflowElement.Element(GetName("firstState")).Element(GetName("viewStateMoniker")).Attribute("name").Value;

            return states.FirstOrDefault(s => s.Name == name);
        }

        private State[] GetStates(XElement webflowElement)
        {
            var states = webflowElement.Elements()
                .Where(e => this.stateTypes.Keys.Contains(e.Name.LocalName))
                .Select(e => new Tuple<State, XElement>(this.stateTypes[e.Name.LocalName](e), e))
                .ToArray();

            this.InitializeTransitions(states);

            return states.Select(e => e.Item1).ToArray();
        }

        private void InitializeTransitions(IEnumerable<Tuple<State, XElement>> states)
        {
            foreach (var state in states)
            {
                state.Item1.Transitions = state.Item2
                    .Elements(GetName("transition"))
                    .Select(e =>
                    {
                        string stateName = e.Elements().First().Attribute("name").Value;
                        return new Transition(e.Attribute("on").Value, states.First(s => s.Item1.Name == stateName).Item1);
                    })
                    .ToArray();
            }
        }
    }
}
